package com.ficus.road.maintain.process;

import com.ficus.road.maintain.config.DiseaseConfig;
import com.ficus.road.maintain.core.model.Confirmation;
import com.ficus.road.maintain.core.model.FrameDTO;
import com.ficus.road.maintain.core.model.Hit;
import com.ficus.road.maintain.service.CarService;
import com.ficus.road.maintain.service.CompanyService;
import com.ficus.road.maintain.service.GpsHistoryService;
import com.ficus.road.maintain.service.HitService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * 病害信息实时处理类
 */
@Slf4j
public class DataProcessor extends BaseProcessor {

    private final int TIME_DURATION_DEFAULT;
    private final int TIME_MINUTE_DURATION_DEFAULT;
    private final int TIME_TRIP_DURATION;

    volatile Map<String, Long> carGpsMap;
    volatile Map<String, Long> carGpsMinuteMap;
    volatile Map<String, Long> carTripMap;
    GpsHistoryService gpsHistoryService;
    CarService carService;
    CompanyService companyService;
    ThreadPoolExecutor saveHitExecutor;
    ThreadPoolExecutor saveMileExecutor;
    HitService hitService;

    public DataProcessor(HitService hitService,
                         CarService carService,
                         GpsHistoryService gpsHistoryService,
                         CompanyService companyService,
                         DiseaseConfig diseaseConfig,
                         int maxDistance, int gpsSaveDuration,
                         int gpsMinuteSaveDuration,
                         int tripSaveDuration,
                         boolean hitCheck) {
        super(diseaseConfig, maxDistance, hitCheck);
        this.hitService = hitService;
        this.gpsHistoryService = gpsHistoryService;
        this.companyService = companyService;
        carGpsMap = Maps.newConcurrentMap();
        carGpsMinuteMap = Maps.newConcurrentMap();
        carTripMap = Maps.newConcurrentMap();
        this.carService = carService;
        this.TIME_DURATION_DEFAULT = gpsSaveDuration;
        this.TIME_MINUTE_DURATION_DEFAULT = gpsMinuteSaveDuration;
        this.TIME_TRIP_DURATION = tripSaveDuration;
        saveHitExecutor = new ThreadPoolExecutor(1, 2,
                10L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(500), new CustomizableThreadFactory("saveHitExecutor-pool-"));
        saveMileExecutor = new ThreadPoolExecutor(1, 2,
                10L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(200), new CustomizableThreadFactory("saveMileExecutor-pool-"));
    }

    @Override
    public int getMaxQueueSize() {
        return 5000;
    }

    @Override
    public Confirmation.ConfirmationStatus getHitStatus() {
        return Confirmation.ConfirmationStatus.TO_BE_CONFIRMED;
    }


    @Override
    public void saveHitInfo(FrameDTO value, List<Hit> hits) {
        if (CollectionUtils.isNotEmpty(hits)) {
            saveHitExecutor.submit(() -> hitService.createHits(hits));
            value.setHits(hits);
            hits.forEach(hit -> hit.setList(null));
        }
        //记录里程信息
        saveMileExecutor.submit(() -> saveMile(value));
    }

    // 实时播放没用到这个uuid
    @Override
    public void sendDrawer(FrameDTO value) {
    }

    @Override
    public boolean isWsConnect(String uuid) {
        return false;
    }

    private void saveMile(FrameDTO frameDTO) {
        String carId = frameDTO.getCarId();
        Double trip = frameDTO.getGpsLocation().getTrip();
        long time = frameDTO.getTimeStamp() / 1000;
        if (carTripMap.containsKey(carId)) {
            Long lastSaveTripTime = carTripMap.get(carId);
            if (time - lastSaveTripTime < TIME_TRIP_DURATION) {
                return;
            }
        }
        carService.updateCarTrip(carId, trip);
        carTripMap.put(carId, time);
    }
}
